package stub

import (
	"context"
	"errors"
	"reflect"

	"lgrpc/message"
	"lgrpc/serializer"
	"lgrpc/service"
)

type ServerStub struct {
	s           service.Service
	value       reflect.Value
	serializers map[uint8]serializer.Serializer
}

func NewServerStub(s service.Service, value reflect.Value, serializers map[uint8]serializer.Serializer) *ServerStub {
	return &ServerStub{
		s:           s,
		value:       value,
		serializers: serializers,
	}
}

func (s *ServerStub) Invoke(ctx context.Context, req *message.Request) ([]byte, error) {
	ser, ok := s.serializers[req.Serializer]
	if !ok {
		return nil, errors.New("micro: 不支持的序列化协议")
	}

	method := s.value.MethodByName(req.MethodName)
	in := make([]reflect.Value, 2)
	in[0] = reflect.ValueOf(ctx)
	inReq := reflect.New(method.Type().In(1).Elem())

	err := ser.Decode(req.Data, inReq.Interface())
	if err != nil {
		return nil, err
	}

	in[1] = inReq
	results := method.Call(in)

	if results[1].Interface() != nil {
		err = results[1].Interface().(error)
	}

	var res []byte
	if results[0].IsNil() {
		return nil, err
	} else {
		var er error
		res, er = ser.Encode(results[0].Interface())
		if er != nil {
			return nil, er
		}
	}
	return res, err
}
